// ============================================================================
//
// Copyright (C) 2006-2007 Dengues
//
// Google Group: http://groups.google.com/group/dengues
// QQ Group: 24885404
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// ============================================================================
package org.dengues.warehouse.viewers;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.dengues.commons.IDenguesSharedImage;
import org.dengues.commons.utils.ImageUtil;
import org.dengues.core.editor.utils.GEFEditorUtils;
import org.dengues.core.metadata.MetadataHelper;
import org.dengues.core.metadata.MetadataTable;
import org.dengues.core.resource.DenguesResourceManager;
import org.dengues.core.resource.WarehouseResourceFactory;
import org.dengues.core.warehouse.ENavNodeType;
import org.dengues.core.warehouse.ENodeCategoryName;
import org.dengues.core.warehouse.ENodeStatus;
import org.dengues.core.warehouse.IWarehouseNode;
import org.dengues.core.warehouse.IWarehouseObject;
import org.dengues.core.warehouse.IWarehouseView;
import org.dengues.model.database.DBTable;
import org.dengues.model.database.DatabaseDiagram;
import org.dengues.model.database.EMFDataType;
import org.dengues.model.warehouse.ProcessType;
import org.dengues.warehouse.models.FolderWarehouseNode;
import org.dengues.warehouse.models.WarehouseNode;
import org.dengues.warehouse.models.WarehouseObject;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.runtime.IPath;
import org.eclipse.emf.common.util.EList;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.viewers.DecorationOverlayIcon;
import org.eclipse.jface.viewers.IDecoration;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.graphics.Image;

/**
 * Qiang.Zhang.Adolf@gmail.com class global comment. Detailled comment <br/>
 * 
 * $Id: Dengues.epf 2007-12-10 qiang.zhang $
 * 
 */
public class WarehouseViewProvider extends LabelProvider implements IStructuredContentProvider, ITreeContentProvider {

    private static Map<String, MetadataTable> warehouseTables = new HashMap<String, MetadataTable>();

    private static List<DatabaseDiagram> warehouseQueries = new ArrayList<DatabaseDiagram>();

    private final IWarehouseView view;

    private WarehouseNode root;

    private WarehouseNode binNode, dbNode, processNode, dataSourceNode;

    private final WarehouseViewFactory viewFactory = new WarehouseViewFactory();

    private WarehouseNode flatFileNode;

    private WarehouseNode xmlFileNode;

    private WarehouseNode webServiceNode;

    /**
     * Qiang.Zhang.Adolf@gmail.com WarehouseViewProvider constructor comment.
     * 
     * @param viewer
     */
    public WarehouseViewProvider(IWarehouseView viewer) {
        super();
        this.view = viewer;
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer, java.lang.Object,
     * java.lang.Object)
     */
    public void inputChanged(Viewer v, Object oldInput, Object newInput) {
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.jface.viewers.IStructuredContentProvider#getElements(java.lang.Object)
     */
    public Object[] getElements(Object parent) {
        if (parent.equals(view.getViewSite())) {
            root = (WarehouseNode) view.getRoot();
            if (root.getChildren().isEmpty()) {
                initialize();
            }
            return root.getChildren().toArray(new WarehouseNode[0]);
        }
        return getChildren(parent);
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.jface.viewers.ITreeContentProvider#getParent(java.lang.Object)
     */
    public Object getParent(Object child) {
        if (child instanceof WarehouseNode) {
            return ((WarehouseNode) child).getParent();
        }
        return null;
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.jface.viewers.ITreeContentProvider#getChildren(java.lang.Object)
     */
    public Object[] getChildren(Object parent) {
        WarehouseNode pp = (WarehouseNode) parent;
        if (!pp.isInitialized()) {
            try {
                if (pp == processNode) {
                    convert(ENodeCategoryName.PROCESS, processNode);
                } else if (pp == dbNode) {
                    // warehouseTables.clear();
                    // convert(ENodeCategoryName.DATABASE, dbNode, binNode);
                } else if (pp == flatFileNode) {
                    // convert(ENodeCategoryName.FLATFILE, flatFileNode, binNode);
                } else if (pp == xmlFileNode) {
                    // convert(ENodeCategoryName.XMLFILE, xmlFileNode, binNode);
                } else if (pp == webServiceNode) {
                    // convert(ENodeCategoryName.WEBSERVICE, webServiceNode, binNode);
                } else if (pp == dataSourceNode) {
                    warehouseTables.clear();
                    warehouseQueries.clear();
                    convert(ENodeCategoryName.DATABASE, dbNode);
                    convert(ENodeCategoryName.WEBSERVICE, webServiceNode);
                    convert(ENodeCategoryName.XMLFILE, xmlFileNode);
                    convert(ENodeCategoryName.FLATFILE, flatFileNode);
                }
                pp.setInitialized(true);
            } catch (Exception e) {
                e.printStackTrace();
            }

        }
        return pp.getChildren().toArray(new WarehouseNode[0]);
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "convert".
     * 
     * @param categoryName
     * @param parentNode
     */
    private void convert(ENodeCategoryName categoryName, WarehouseNode parentNode) {
        IPath warehousePath = parentNode.getWarehousePath();
        List<Object> objectsFromEMF = WarehouseResourceFactory.getObjectFromEMF(categoryName, warehousePath);
        for (Object object : objectsFromEMF) {
            if (object instanceof IFolder) {
                IFolder folder = ((IFolder) object);
                if (!folder.getName().equalsIgnoreCase(ENodeCategoryName.BIN.getName())) {
                    FolderWarehouseNode folderNode = new FolderWarehouseNode(parentNode, folder.getName());
                    folderNode.setCategoryName(categoryName);
                    parentNode.getChildren().add(folderNode);
                    convert(categoryName, folderNode);
                }
            }
        }
        addWarehouseNode(categoryName, warehousePath, parentNode);

    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "addWarehouseNode".
     * 
     * @param categoryName
     * @param warehousePath
     * @param parentNode
     */
    private void addWarehouseNode(ENodeCategoryName categoryName, IPath warehousePath, WarehouseNode parentNode) {
        List<IWarehouseObject> objectsFromEMF = viewFactory.getObjectsFromEMF(categoryName, warehousePath);
        for (IWarehouseObject object : objectsFromEMF) {
            if (object.getCategoryName() == ENodeCategoryName.PROCESS) {
                ProcessType processType = (ProcessType) object.getData();
                if (processType.getStatus().equals(ENodeStatus.DELETED.getId())) {
                    WarehouseNode child = new WarehouseNode(object, binNode, ENavNodeType.ELEMENT);
                    child.setBin(true);
                    child.setCategoryName(ENodeCategoryName.PROCESS);
                    child.setNodeType(ENavNodeType.ELEMENT);
                    child.setLabel(processType.getName());
                    binNode.getChildren().add(child);
                } else {
                    WarehouseNode child = new WarehouseNode(object, parentNode, ENavNodeType.ELEMENT);
                    child.setLabel(processType.getName());
                    child.setCategoryName(ENodeCategoryName.PROCESS);
                    child.setNodeType(ENavNodeType.ELEMENT);
                    if (GEFEditorUtils.isNodeActived(processType.getName(), categoryName)) {
                        child.setNodeStatus(ENodeStatus.ACTIVED);
                    }
                    parentNode.getChildren().add(child);
                }
            } else if (object.getCategoryName() == ENodeCategoryName.DATABASE) {
                DatabaseDiagram db = (DatabaseDiagram) object.getData();
                if (db.getStatus().equals(ENodeStatus.DELETED.getId())) {
                    WarehouseNode child = new WarehouseNode(object, binNode, ENavNodeType.ELEMENT);
                    child.setBin(true);
                    int value = db.getEmfType().getValue();
                    switch (value) {
                    case EMFDataType.QUERY:
                        child.setCategoryName(ENodeCategoryName.QUERY);
                        break;
                    case EMFDataType.DATABASE:
                        child.setCategoryName(ENodeCategoryName.DATABASE);
                        break;
                    }
                    child.setNodeType(ENavNodeType.ELEMENT);
                    child.setLabel(db.getName());
                    binNode.getChildren().add(child);
                } else {
                    WarehouseNode child = new WarehouseNode(object, parentNode, ENavNodeType.ELEMENT);
                    child.setLabel(db.getName());
                    int value = db.getEmfType().getValue();
                    ENodeCategoryName cName = ENodeCategoryName.DATABASE;
                    switch (value) {
                    case EMFDataType.QUERY:
                        cName = ENodeCategoryName.QUERY;
                        warehouseQueries.add(db);
                        break;
                    }
                    child.setCategoryName(cName);
                    if (GEFEditorUtils.isNodeActived(db.getName(), categoryName)) {
                        child.setNodeStatus(ENodeStatus.ACTIVED);
                    }
                    child.setNodeType(ENavNodeType.ELEMENT);
                    parentNode.getChildren().add(child);
                    addWarehouseTables(warehousePath, db, child);
                }
            }
        }
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "addWarehouseTables".
     * 
     * @param warehousePath
     * 
     * @param db
     * @param dbNode
     */
    private void addWarehouseTables(IPath warehousePath, DatabaseDiagram db, WarehouseNode dbNode) {
        EList dbChildren = db.getDbChildren();
        for (Object object : dbChildren) {
            if (object instanceof DBTable) {
                MetadataTable metadataTable = MetadataHelper.convertMetadataTable((DBTable) object);
                warehouseTables.put(IPath.SEPARATOR + warehousePath.toPortableString() + "->" + db.getName() + ":"
                        + metadataTable.getTableName(), metadataTable);
            }
            addDbChildrenNode(ENodeCategoryName.TABLE, dbNode, object);
        }
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "addDbChildrenNode".
     * 
     * @param table
     * @param dbNode2
     * @param object
     */
    private void addDbChildrenNode(ENodeCategoryName table, WarehouseNode dbNode2, Object object) {
        if (object instanceof DBTable) {
            DBTable db = (DBTable) object;
            WarehouseObject object2 = new WarehouseObject(object);
            WarehouseNode child = new WarehouseNode(object2, dbNode2, ENavNodeType.ELEMENT);
            child.setLabel(db.getName());
            child.setCategoryName(ENodeCategoryName.TABLE);
            child.setNodeType(ENavNodeType.ELEMENT);
            dbNode2.getChildren().add(child);
        }
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "initialize".
     */
    private void initialize() {
        DenguesResourceManager.resetResourceSet();
        List<IWarehouseNode> nodes = root.getChildren();
        binNode = new WarehouseNode(null, root, ENavNodeType.SYSTEM_FOLDER);
        binNode.setCategoryName(ENodeCategoryName.BIN);
        binNode.setImage(ImageUtil.getImage(IDenguesSharedImage.VIEW_TRASH));
        binNode.setBin(true);
        nodes.add(binNode);

        dataSourceNode = new WarehouseNode(null, root, ENavNodeType.SYSTEM_FOLDER);
        dataSourceNode.setCategoryName(ENodeCategoryName.DATASOURCE);
        nodes.add(dataSourceNode);

        dbNode = new WarehouseNode(null, dataSourceNode, ENavNodeType.SYSTEM_FOLDER);
        dbNode.setCategoryName(ENodeCategoryName.DATABASE);
        dbNode.setImage(ImageUtil.getImage(IDenguesSharedImage.VIEW_DATA));
        dataSourceNode.getChildren().add(dbNode);

        flatFileNode = new WarehouseNode(null, dataSourceNode, ENavNodeType.SYSTEM_FOLDER);
        flatFileNode.setCategoryName(ENodeCategoryName.FLATFILE);
        flatFileNode.setImage(ImageUtil.getImage(IDenguesSharedImage.QUERSTION));
        dataSourceNode.getChildren().add(flatFileNode);

        xmlFileNode = new WarehouseNode(null, dataSourceNode, ENavNodeType.SYSTEM_FOLDER);
        xmlFileNode.setCategoryName(ENodeCategoryName.XMLFILE);
        xmlFileNode.setImage(ImageUtil.getImage(IDenguesSharedImage.QUERSTION));
        dataSourceNode.getChildren().add(xmlFileNode);

        webServiceNode = new WarehouseNode(null, dataSourceNode, ENavNodeType.SYSTEM_FOLDER);
        webServiceNode.setCategoryName(ENodeCategoryName.WEBSERVICE);
        webServiceNode.setImage(ImageUtil.getImage(IDenguesSharedImage.QUERSTION));
        dataSourceNode.getChildren().add(webServiceNode);

        processNode = new WarehouseNode(null, root, ENavNodeType.SYSTEM_FOLDER);
        processNode.setCategoryName(ENodeCategoryName.PROCESS);
        processNode.setImage(ImageUtil.getImage(IDenguesSharedImage.VIEW_PROCESS));
        nodes.add(processNode);
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.jface.viewers.ITreeContentProvider#hasChildren(java.lang.Object)
     */
    public boolean hasChildren(Object parent) {
        return getChildren(parent).length > 0;
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.jface.viewers.LabelProvider#getText(java.lang.Object)
     */
    @Override
    public String getText(Object obj) {
        if (obj instanceof WarehouseNode) {
            return ((WarehouseNode) obj).getLabel();
        }
        return obj.toString();
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.jface.viewers.LabelProvider#getImage(java.lang.Object)
     */
    @Override
    public Image getImage(Object obj) {
        if (obj instanceof WarehouseNode) {
            WarehouseNode warehouseNode = ((WarehouseNode) obj);
            if (warehouseNode.getNodeType().equals(ENavNodeType.SIMPLE_FOLDER)) {
                if (view.isExpanded(warehouseNode)) {
                    return ImageUtil.getImage(IDenguesSharedImage.WAREHOUSE_FOLDER_OPEN);
                }
                return ImageUtil.getImage(IDenguesSharedImage.WAREHOUSE_FOLDER_CLOSE);
            }
            ENodeCategoryName categoryName = warehouseNode.getCategoryName();
            Image image;
            switch (categoryName) {
            case PROCESS:
                image = ImageUtil.getImage(IDenguesSharedImage.VIEW_PROCESS);
                return getOverlayIcon(warehouseNode, image);
            case QUERY:
                image = ImageUtil.getImage(IDenguesSharedImage.VIEW_QUERY);
                return getOverlayIcon(warehouseNode, image);
            case DATABASE: {
                image = ImageUtil.getImage(IDenguesSharedImage.VIEW_DATA);
                return getOverlayIcon(warehouseNode, image);
            }
            case DATASOURCE:
                return ImageUtil.getImage(IDenguesSharedImage.VIEW_DATASOURCE);
            case TABLE:
                return ImageUtil.getImage(IDenguesSharedImage.VIEW_TABLE);
            case BIN:
                return ImageUtil.getImage(IDenguesSharedImage.VIEW_TRASH);
                // case XMLFILE:
                // return xmlFileNode.getImage();
                // case WEBSERVICE:
                // return webServiceNode.getImage();
                // case FLATFILE:
                // return ImageUtil.getImage(IDenguesSharedImage.QUERSTION);
            default:
                return ImageUtil.getImage(IDenguesSharedImage.QUERSTION);
            }
        }
        return null;
    }

    private final ImageDescriptor overlayImage = ImageUtil.getDescriptor(IDenguesSharedImage.VIEW_LOCKED);

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "getOverlayIcon".
     * 
     * @param object
     * @param baseImage
     * @return
     */
    private Image getOverlayIcon(WarehouseNode node, Image baseImage) {
        Image image = baseImage;
        if (node != null) {
            ENodeStatus data2 = node.getNodeStatus();
            String status = data2.getId();
            if (status.equals(ENodeStatus.ACTIVED.getId())) {
                DecorationOverlayIcon icon = new DecorationOverlayIcon(baseImage, overlayImage, IDecoration.TOP_RIGHT);
                image = icon.createImage();
            }
        }
        return image;
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "getWarehouseTables".
     * 
     * @return
     */
    public static Map<String, MetadataTable> getWarehouseTables() {
        return warehouseTables;
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "getWarehouseQueries".
     * 
     * @return
     */
    public static List<DatabaseDiagram> getWarehouseQueries() {
        return warehouseQueries;
    }
}
